#region Copyright (c) 2003-2007, Luke T. Maxon



/********************************************************************************************************************

'

' Copyright (c) 2003-2007, Luke T. Maxon

' All rights reserved.

' 

' Redistribution and use in source and binary forms, with or without modification, are permitted provided

' that the following conditions are met:

' 

' * Redistributions of source code must retain the above copyright notice, this list of conditions and the

' 	following disclaimer.

' 

' * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and

' 	the following disclaimer in the documentation and/or other materials provided with the distribution.

' 

' * Neither the name of the author nor the names of its contributors may be used to endorse or 

' 	promote products derived from this software without specific prior written permission.

' 

' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED

' WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A

' PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR

' ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

' INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,

' OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN

' IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

'

'*******************************************************************************************************************/



#endregion



using System.Windows.Forms;

using System.Collections.Generic;

using System;

using System.ComponentModel;



namespace SuedeTest.Core {

   /// <summary>

   /// Internal use only.  Finds controls, components, and menuitems

   /// according to their name property.

   /// </summary>

   /// <remarks>

   /// It is also used by the recorder application which is why it is not

   /// internal.

   /// </remarks>

   /// the recorder application.

   public class Finder<T> {

      private readonly string name;

      private static List<Form> forms = null;



      public Finder() { }



      /// <summary>

      /// Creates a Finder that will find things on a specific Form according to their name.

      /// </summary>

      /// <param name="name">The name of the Control to find.</param>

      /// <param name="form">The form to search for the control.</param>

      public Finder(string name, Form form) {

         this.name = name;

         if (form != null) {

            forms = new List<Form>();

            forms.Add(form);

         }

      }



      /// <summary>

      /// Creates a Finder that will find things according to their name.  

      /// </summary>

      /// <param name="name">The name of the thing to find.</param>

      public Finder(string name) {

         this.name = name;

      }



      /// <summary>

      /// Finds a control.  

      /// </summary>

      /// <exception>

      /// If there is more than one with the specified name, it will

      /// throw an AmbiguousNameException.  If the Control does not exist, it will throw

      /// a NoSuchControlException.

      /// </exception>

      /// <returns>The control if one is found.</returns>

      public T Find() {

         return (T)Find(typeof(T));

      }



      public int Count {

         get {

            return FindAll(typeof(T)).Count;

         }

      }



      private List<Form> FormCollection {

         get {

            return FormRepository.Forms;

         }

      }

      

      private List<Object> FindAll() {

         List<Object> found = new List<Object>();

         List<Form> forms = FormCollection;

         lock (forms) {

            foreach (Form form in forms) {

               found.AddRange(Find(name, form));

            }

         }

         return found;

      }



      private List<Object> FindAll(Type type) {

         List<Object> found = new List<object>();

         List<Object> allFound = FindAll();

         foreach (object o in allFound) {

            if (type.IsAssignableFrom(o.GetType())) {

               found.Add(o);

            }

         }

         return found;

      }



      private Object Find(Type type) {

         List<Object> found = FindAll(type);

         if (found.Count == 1) {

            return found[0];

         } else if (found.Count == 0) {

            throw new NoSuchControlException(name);

         } else {

            throw new AmbiguousNameException(name);

         }

      }



      private List<object> Find(string name, object obj) {



         List<object> results = new List<object>();



         if (obj == null) {

            return results;

         }



         string objName = Name(obj);



         if (objName == name) {

            results.Add(obj);

         } else if (name.StartsWith(objName)) {

            //+1 to remove trailing '.'

            string subName = name.Substring(objName.Length + 1);



            if (obj is Form) {

               results.AddRange(Find(subName, (obj as Form).Menu));

            }



            if (obj is ToolStrip) {

               ToolStrip t = obj as ToolStrip;

               foreach (ToolStripItem t2 in t.Items) {

                  results.AddRange(Find(subName, t2));

               }

            }



            if (obj is ToolStripDropDownItem) {

               ToolStripDropDownItem i = obj as ToolStripDropDownItem;

               foreach (ToolStripItem i2 in i.DropDownItems) {

                  results.AddRange(Find(subName, i2));

               }

            }



            if (obj is Menu) {

               Menu m = obj as Menu;

               foreach (MenuItem m2 in m.MenuItems) {

                  results.AddRange(Find(subName, m2));

               }

            }



            if (obj is Control) {

               Control c = obj as Control;

               foreach (Control c2 in c.Controls) {

                  results.AddRange(Find(subName, c2));

               }

            }

         }

         return results;

      }



      //XXX should be a utility method somewhere

      public string Name(object o) {

         if (o is ToolStripControlHost) {

            return ((ToolStripControlHost)o).Name;

         }



         if (o is ToolStripItem) {

            return ((ToolStripItem)o).Text.Replace("&", string.Empty).Replace(".", string.Empty);

         }

         if (o is Control) {

            return ((Control)o).Name;

         }

         if (o is MenuItem) {

            return ((MenuItem)o).Text.Replace("&", string.Empty).Replace(".", string.Empty);

         }

         if (o is MainMenu) {

            return "MainMenu";

         }

         if (o is ContextMenu) {

            return "ContextMenu";

         }

         if (o is Component) {

            return ((Component)o).Site.Name;

         }

         throw new Exception("Object name not defined");

      }

   }

}